import org.junit.*;

import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;

/**
 * Date: 05.03.13
 * Time: 14:07
 */
public class BoardTest {
    private static Board size1Board;
    private static Board size2Board;
    private static Board size3BoardSolvable;
    private static Board size3BoardUnsolvable;
    private static Board size3BoardGoal;
    private static Board size3BoardSolvableForEqualsTest;

    @BeforeClass
    public static void setUp() throws Exception {
        int[][] size1Grid = {{0}};

        int[][] size2Grid = {{1, 0},
                             {3, 2}};

        int[][] size3GridSolvable = {{8, 1, 3},
                                     {4, 0, 2},
                                     {7, 6, 5}}; //not sure if solvable

        int[][] size3GridUnsolvable = {{1, 2, 3},
                                       {4, 6, 5},
                                       {7, 8, 0}};

        int[][] size3GridGoal = {{1, 2, 3},
                                 {4, 5, 6},
                                 {7, 8, 0}};

        size1Board = new Board(size1Grid);
        size2Board = new Board(size2Grid);
        size3BoardSolvable = new Board(size3GridSolvable);
        size3BoardSolvableForEqualsTest = new Board(size3GridSolvable);
        size3BoardUnsolvable = new Board(size3GridUnsolvable);
        size3BoardGoal = new Board(size3GridGoal);
    }

    @Test
    public void testDimension() throws Exception {
        assertEquals("Wrong dimension", 1, size1Board.dimension());
        assertEquals("Wrong dimension", 2, size2Board.dimension());
        assertEquals("Wrong dimension", 3, size3BoardSolvable.dimension());
        assertEquals("Wrong dimension", 3, size3BoardUnsolvable.dimension());
    }

    @Test
    public void testHamming() throws Exception {
        assertEquals("Wrong Hamming Calculation", 0, size1Board.hamming());
        assertEquals("Wrong Hamming Calculation", 0, size3BoardGoal.hamming());
        assertEquals("Wrong Hamming Calculation", 1, size2Board.hamming());
        assertEquals("Wrong Hamming Calculation", 5, size3BoardSolvable.hamming());
        assertEquals("Wrong Hamming Calculation", 2, size3BoardUnsolvable.hamming());
    }

    @Test
    public void testManhattan() throws Exception {
        assertEquals("Wrong Manhattan Calculation", 0, size1Board.manhattan());
        assertEquals("Wrong Manhattan Calculation", 0, size3BoardGoal.manhattan());
        assertEquals("Wrong Manhattan Calculation", 1, size2Board.manhattan());
        assertEquals("Wrong Manhattan Calculation", 10, size3BoardSolvable.manhattan());
        assertEquals("Wrong Manhattan Calculation", 2, size3BoardUnsolvable.manhattan());
    }

    @Test
    public void testIsGoal() throws Exception {
        assertTrue("Wrong goal test", size1Board.isGoal());
        assertFalse("Wrong goal test", size2Board.isGoal());
        assertFalse("Wrong goal test", size3BoardSolvable.isGoal());
        assertFalse("Wrong goal test", size3BoardUnsolvable.isGoal());
        assertTrue("Wrong goal test", size3BoardGoal.isGoal());
    }

    @Test
    public void testTwin() throws Exception {
        int[][] twinGrid = {{1, 0},
                            {2, 3}};
        assertTrue(size2Board.twin().equals(new Board(twinGrid)));
        int[][] twinGrid2 = {{1, 8, 3},
                             {4, 0, 2},
                             {7, 6, 5}};
        assertTrue(size3BoardSolvable.twin().equals(new Board(twinGrid2)));
        int[][] twinGrid3 = {{2, 1, 3},
                             {4, 6, 5},
                             {7, 8, 0}};
        assertTrue(size3BoardUnsolvable.twin().equals(new Board(twinGrid3)));

    }

    @Test
    public void testEquals() throws Exception {
        assertFalse("Boards of different sizes can't be equal", size1Board.equals(size2Board));
        assertTrue("Boards created from same grid should be equal",
                size3BoardSolvable.equals(size3BoardSolvableForEqualsTest));
        assertTrue("Board should be equal to itself", size2Board.equals(size2Board));
        assertFalse("Board should not be equal to object of other type", size1Board.equals(new Integer(1)));
        assertFalse("Board should not be equal to null", size1Board.equals(null));
    }

    @Test
    public void testNeighbors() throws Exception {
        int[][] size2GridLeftNeighbor = {{0, 1},
                                          {3, 2}};
        int[][] size2GridBottomNeighbor = {{1, 2},
                                            {3, 0}};
        int count = 0;
//        for (Board board : size2Board.neighbors()) {
//            assertTrue("Wrong neighbour", board.equals(new Board(size2GridLeftNeighbor))
//                    || board.equals(new Board(size2GridBottomNeighbor)));
//            count++;
//        }
//        assertEquals("Wrong amount of neighbors", 2, count);

        int[][] size3GridSolvableLeftNeighbor = {{8, 1, 3},
                                                {0, 4, 2},
                                                {7, 6, 5}};

        int[][] size3GridSolvableRightNeighbor = {{8, 1, 3},
                                                {4, 2, 0},
                                                {7, 6, 5}};

        int[][] size3GridSolvableTopNeighbor = {{8, 0, 3},
                                                {4, 1, 2},
                                                {7, 6, 5}};

        int[][] size3GridSolvableBottomNeighbor = {{8, 1, 3},
                                                {4, 6, 2},
                                                {7, 0, 5}};

        Set<Board> rightNeighbors = new HashSet<Board>();
        rightNeighbors.add(new Board(size3GridSolvableLeftNeighbor));
        rightNeighbors.add(new Board(size3GridSolvableRightNeighbor));
        rightNeighbors.add(new Board(size3GridSolvableTopNeighbor));
        rightNeighbors.add(new Board(size3GridSolvableBottomNeighbor));
        count = 0;
        for (Board board : size3BoardSolvable.neighbors()){
            System.out.println(board);
     //       assertTrue("Wrong neighbour", rightNeighbors.contains(board));
            count++;
        }
        assertEquals("Wrong amount of neighbors",  rightNeighbors.size(), count);

    }
}
